import { Request, Response, NextFunction } from 'express';
import { RateLimiterMemory, RateLimiterRedis } from 'rate-limiter-flexible';
import { Logger } from '@/utils/logger';
import { RateLimitError } from './errorHandler';

const logger = new Logger('RateLimiter');

// 内存存储的速率限制器
const rateLimiterMemory = new RateLimiterMemory({
  keyPrefix: 'middleware',
  points: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'), // 请求次数
  duration: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000') / 1000, // 时间窗口(秒)
});

// 不同端点的速率限制配置
const endpointLimits = {
  '/api/v1/auth/login': {
    points: 5, // 5次尝试
    duration: 900, // 15分钟
    blockDuration: 900, // 阻止15分钟
  },
  '/api/v1/auth/register': {
    points: 3, // 3次注册
    duration: 3600, // 1小时
    blockDuration: 3600, // 阻止1小时
  },
  '/api/v1/auth/forgot-password': {
    points: 3, // 3次请求
    duration: 3600, // 1小时
    blockDuration: 3600, // 阻止1小时
  }
};

// 创建特定端点的限制器
const endpointLimiters = Object.entries(endpointLimits).reduce((acc, [endpoint, config]) => {
  acc[endpoint] = new RateLimiterMemory({
    keyPrefix: `endpoint_${endpoint.replace(/[^a-zA-Z0-9]/g, '_')}`,
    ...config
  });
  return acc;
}, {} as Record<string, RateLimiterMemory>);

// 基于IP的严格限制器（防止暴力攻击）
const strictLimiter = new RateLimiterMemory({
  keyPrefix: 'strict',
  points: 1000, // 1000次请求
  duration: 3600, // 1小时
  blockDuration: 3600, // 阻止1小时
});

// 基于用户的限制器
const userLimiter = new RateLimiterMemory({
  keyPrefix: 'user',
  points: 1000, // 1000次请求
  duration: 3600, // 1小时
  blockDuration: 300, // 阻止5分钟
});

export const rateLimiter = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
  try {
    const key = req.ip;
    const endpoint = req.route?.path || req.path;
    const fullPath = `${req.method} ${endpoint}`;

    // 检查是否有特定端点的限制器
    const specificLimiter = endpointLimiters[fullPath] || endpointLimiters[endpoint];
    
    if (specificLimiter) {
      // 使用特定端点的限制器
      await specificLimiter.consume(key);
      logger.debug(`Rate limit check passed for ${fullPath}`, { ip: key });
    } else {
      // 使用通用限制器
      await rateLimiterMemory.consume(key);
      logger.debug(`General rate limit check passed`, { ip: key, endpoint: fullPath });
    }

    // 严格限制检查（防止恶意攻击）
    await strictLimiter.consume(key);

    // 如果用户已认证，还要检查用户级别的限制
    if (req.user?.id) {
      await userLimiter.consume(req.user.id);
    }

    next();
  } catch (rejRes: any) {
    // 速率限制触发
    const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
    
    logger.warn('Rate limit exceeded', {
      ip: req.ip,
      endpoint: req.path,
      method: req.method,
      resetTime: secs,
      userAgent: req.get('User-Agent')
    });

    // 设置响应头
    res.set('Retry-After', String(secs));
    res.set('X-RateLimit-Limit', String(rejRes.totalHits || 100));
    res.set('X-RateLimit-Remaining', String(rejRes.remainingPoints || 0));
    res.set('X-RateLimit-Reset', String(new Date(Date.now() + rejRes.msBeforeNext)));

    // 返回429错误
    const error = new RateLimitError(`请求过于频繁，请在${secs}秒后重试`);
    next(error);
  }
};

// 验证码相关的特殊限制器
export const captchaLimiter = new RateLimiterMemory({
  keyPrefix: 'captcha',
  points: 10, // 10次验证码请求
  duration: 3600, // 1小时
  blockDuration: 3600, // 阻止1小时
});

// 短信验证码限制器
export const smsLimiter = new RateLimiterMemory({
  keyPrefix: 'sms',
  points: 5, // 5条短信
  duration: 3600, // 1小时
  blockDuration: 3600, // 阻止1小时
});

// 创建自定义限制器中间件
export const createRateLimiter = (options: {
  points: number;
  duration: number;
  blockDuration?: number;
  keyGenerator?: (req: Request) => string;
  skipSuccessfulRequests?: boolean;
  skipFailedRequests?: boolean;
}) => {
  const limiter = new RateLimiterMemory({
    keyPrefix: 'custom',
    points: options.points,
    duration: options.duration,
    blockDuration: options.blockDuration || options.duration,
  });

  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const key = options.keyGenerator ? options.keyGenerator(req) : req.ip;
      await limiter.consume(key);
      next();
    } catch (rejRes: any) {
      const secs = Math.round(rejRes.msBeforeNext / 1000) || 1;
      
      logger.warn('Custom rate limit exceeded', {
        key: options.keyGenerator ? options.keyGenerator(req) : req.ip,
        endpoint: req.path,
        resetTime: secs
      });

      res.set('Retry-After', String(secs));
      const error = new RateLimitError(`请求过于频繁，请在${secs}秒后重试`);
      next(error);
    }
  };
};